/*******************************************************************************
* Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt
******************************************************************************/
package com.opendoorlogistics.core.utils.images;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.opendoorlogistics.codefromweb.hqx.Hqx_2x;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
final public class ImageUtils {
public static Dimension getSize(BufferedImage image){
return new Dimension(image.getWidth(), image.getHeight());
}
/**
* Decode string to image
*
* @param imageString
* The string to decode
* @return decoded image
*/
public static BufferedImage base64StringToImage(String imageString) {
BufferedImage ret = null;
byte[] imageByte;
try {
BASE64Decoder decoder = new BASE64Decoder();
imageByte = decoder.decodeBuffer(imageString);
ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
ret = ImageIO.read(bis);
bis.close();
} catch (Throwable e) {
}
return ret;
}
/**
* Encode image to string
*
* @param image
* The image to encode
* @param type
* jpeg, bmp, ...
* @return encoded string
*/
public static String imageToBase64String(RenderedImage image, String type) {
String ret = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ImageIO.write(image, type, bos);
byte[] bytes = bos.toByteArray();
BASE64Encoder encoder = new BASE64Encoder();
ret = encoder.encode(bytes);
ret = ret.replace(System.lineSeparator(), "");
} catch (IOException e) {
throw new RuntimeException();
}
return ret;
}
/**
* Add the input images together
*
* @param images
* @return
*/
public static BufferedImage addImages(BufferedImage... images) {
if (images.length == 0) {
throw new IllegalArgumentException();
} else if (images.length == 1) {
return images[0];
}
// general case
BufferedImage ret = deepCopy(images[0]);
Graphics2D g = ret.createGraphics();
try {
g.setClip(0, 0, ret.getWidth(), ret.getHeight());
for (int i = 1; i < images.length; i++) {
g.drawImage(images[i], 0, 0, null);
}
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
if (g != null) {
g.dispose();
}
}
return ret;
}
public static BufferedImage createBlankImage(int width, int height, Color color) {
int type = BufferedImage.TYPE_INT_RGB;
return createBlankImage(width, height, type, color);
}
public static BufferedImage createBlankImage(int width, int height, int type, Color color) {
BufferedImage image = new BufferedImage(width, height, type);
fillImage(image, color);
return image;
}
public static byte[] toPNG(BufferedImage img) {
return toByteArray(img, "png");
}
public static byte[] toBMP(BufferedImage img) {
return toByteArray(img, "BMP");
}
private static byte[] toByteArray(BufferedImage img, String imageFileType) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img, imageFileType, baos);
return baos.toByteArray();
} catch (Throwable e) {
throw new RuntimeException();
}
}
public static void toPNGFile(RenderedImage img, File file){
try{
ImageIO.write(img, "png",file);
}catch(Exception e){
throw new RuntimeException(e);
}
}
public static BufferedImage fromPNG(byte[] bytes) {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try {
return ImageIO.read(bais);
} catch (Throwable e) {
throw new RuntimeException();
}
}
public static void fillImage(BufferedImage image, Color color) {
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.dispose();
}
public static void showImage(Image image) {
createImageFrame(image).setVisible(true);
}
public static JFrame createImageFrame(Image image) {
JFrame ret = new JFrame();
ret.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ret.add(createImagePanel(image, null));
ret.pack();
return ret;
}
public static JInternalFrame createImageInternalFrame(Image image, Color backgroundColour) {
JInternalFrame ret = new JInternalFrame();
ret.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ret.add(new JScrollPane(createImagePanel(image, backgroundColour)));
ret.pack();
if (backgroundColour != null) {
ret.setBackground(backgroundColour);
}
return ret;
}
public static JPanel createImagePanel(Image image, Color backColor) {
JPanel panel = new JPanel();
panel.add(new JLabel(new ImageIcon(image)));
if (backColor != null) {
panel.setBackground(backColor);
}
return panel;
}
/**
* Scale the image by the input fraction using a combination of Hqx 2x and bicubic interpolation. Hqx 2x applied multiplied times gives better
* looking results than Hqx 4x applied less times. Bicubic interpolation is used to do any scaling that's less than 2 times the original (or
* downscaling).
*
* @param image
* @param fraction
* @return
*/
public static BufferedImage scaleImage(BufferedImage image, Dimension newSize) {
class Scaler {
BufferedImage scaleImage(BufferedImage image, Dimension newSize) {
while (true) {
double xFraction = Math.round(newSize.getWidth() / image.getWidth());
double yFraction = Math.round(newSize.getHeight() / image.getHeight());
if (xFraction > 1.5 && yFraction > 1.5) {
// double using hqx_2x (repeated doubles give better quality than hqx_4x )
image = hq2x(image);
} else {
// use bicubic interpolation to get to exact fraction
image = bicubicScaling(image, newSize);
return image;
}
}
}
private BufferedImage bicubicScaling(BufferedImage image, Dimension newSize) {
BufferedImage newImage = ImageUtils.createBlankImage(newSize.width, newSize.height, Color.WHITE);
Graphics2D g2 = (Graphics2D) newImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.drawImage(image, 0, 0, newSize.width, newSize.height, null);
g2.dispose();
return newImage;
}
private BufferedImage hq2x(BufferedImage image) {
int nw = image.getWidth() * 2;
int nh = image.getHeight() * 2;
BufferedImage newImage = ImageUtils.createBlankImage(nw, nh, Color.WHITE);
// test upscaling...
int[] rgb = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
int[] upscaled = new int[nw * nh];
Hqx_2x.hq2x_32_rb(rgb, upscaled, image.getWidth(), image.getHeight());
newImage.setRGB(0, 0, newImage.getWidth(), newImage.getHeight(), upscaled, 0, newImage.getWidth());
return newImage;
}
}
return new Scaler().scaleImage(image, newSize);
}
/**
* See http://stackoverflow.com/questions/3514158/how-do-you-clone-a-bufferedimage
*
* @param bi
* @return
*/
public static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
/**
* See http://stackoverflow.com/questions/13605248/java-converting-image-to-bufferedimage
*
* @param img
* @return
*/
public static BufferedImage toBufferedImage(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
public static void main(String []args)throws Exception{
BufferedImage img = ImageIO.read(new File("img.png"));
img = scaleImage(img, new Dimension(img.getWidth()*2, img.getHeight()*2));
ImageIO.write(img, "png",new File("upscaled.png"));
}
}